home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / Kubuntu 8.10 / kubuntu-8.10-desktop-i386.iso / casper / filesystem.squashfs / usr / lib / ruby / 1.8 / resolv.rb < prev    next >
Text File  |  2008-08-07  |  57KB  |  2,257 lines

  1. require 'socket'
  2. require 'fcntl'
  3. require 'timeout'
  4. require 'thread'
  5.  
  6. begin
  7.   require 'securerandom'
  8. rescue LoadError
  9. end
  10.  
  11. # Resolv is a thread-aware DNS resolver library written in Ruby.  Resolv can
  12. # handle multiple DNS requests concurrently without blocking.  The ruby
  13. # interpreter.
  14. #
  15. # See also resolv-replace.rb to replace the libc resolver with # Resolv.
  16. # Resolv can look up various DNS resources using the DNS module directly.
  17. # Examples:
  18. #   p Resolv.getaddress "www.ruby-lang.org"
  19. #   p Resolv.getname "210.251.121.214"
  20. #   Resolv::DNS.open do |dns|
  21. #     ress = dns.getresources "www.ruby-lang.org", Resolv::DNS::Resource::IN::A
  22. #     p ress.map { |r| r.address }
  23. #     ress = dns.getresources "ruby-lang.org", Resolv::DNS::Resource::IN::MX
  24. #     p ress.map { |r| [r.exchange.to_s, r.preference] }
  25. #   end
  26. # == Bugs
  27. # * NIS is not supported.
  28. # * /etc/nsswitch.conf is not supported.
  29.  
  30. class Resolv
  31.  
  32.   ##
  33.   # Looks up the first IP address for +name+.
  34.   
  35.   def self.getaddress(name)
  36.     DefaultResolver.getaddress(name)
  37.   end
  38.  
  39.   ##
  40.   # Looks up all IP address for +name+.
  41.   
  42.   def self.getaddresses(name)
  43.     DefaultResolver.getaddresses(name)
  44.   end
  45.  
  46.   ##
  47.   # Iterates over all IP addresses for +name+.
  48.  
  49.   def self.each_address(name, &block)
  50.     DefaultResolver.each_address(name, &block)
  51.   end
  52.  
  53.   ##
  54.   # Looks up the hostname of +address+.
  55.  
  56.   def self.getname(address)
  57.     DefaultResolver.getname(address)
  58.   end
  59.  
  60.   ##
  61.   # Looks up all hostnames for +address+.
  62.  
  63.   def self.getnames(address)
  64.     DefaultResolver.getnames(address)
  65.   end
  66.  
  67.   ##
  68.   # Iterates over all hostnames for +address+.
  69.  
  70.   def self.each_name(address, &proc)
  71.     DefaultResolver.each_name(address, &proc)
  72.   end
  73.  
  74.   ##
  75.   # Creates a new Resolv using +resolvers+.
  76.  
  77.   def initialize(resolvers=[Hosts.new, DNS.new])
  78.     @resolvers = resolvers
  79.   end
  80.  
  81.   ##
  82.   # Looks up the first IP address for +name+.
  83.   
  84.   def getaddress(name)
  85.     each_address(name) {|address| return address}
  86.     raise ResolvError.new("no address for #{name}")
  87.   end
  88.  
  89.   ##
  90.   # Looks up all IP address for +name+.
  91.   
  92.   def getaddresses(name)
  93.     ret = []
  94.     each_address(name) {|address| ret << address}
  95.     return ret
  96.   end
  97.  
  98.   ##
  99.   # Iterates over all IP addresses for +name+.
  100.  
  101.   def each_address(name)
  102.     if AddressRegex =~ name
  103.       yield name
  104.       return
  105.     end
  106.     yielded = false
  107.     @resolvers.each {|r|
  108.       r.each_address(name) {|address|
  109.         yield address.to_s
  110.         yielded = true
  111.       }
  112.       return if yielded
  113.     }
  114.   end
  115.  
  116.   ##
  117.   # Looks up the hostname of +address+.
  118.  
  119.   def getname(address)
  120.     each_name(address) {|name| return name}
  121.     raise ResolvError.new("no name for #{address}")
  122.   end
  123.  
  124.   ##
  125.   # Looks up all hostnames for +address+.
  126.  
  127.   def getnames(address)
  128.     ret = []
  129.     each_name(address) {|name| ret << name}
  130.     return ret
  131.   end
  132.  
  133.   ##
  134.   # Iterates over all hostnames for +address+.
  135.  
  136.   def each_name(address)
  137.     yielded = false
  138.     @resolvers.each {|r|
  139.       r.each_name(address) {|name|
  140.         yield name.to_s
  141.         yielded = true
  142.       }
  143.       return if yielded
  144.     }
  145.   end
  146.  
  147.   ##
  148.   # Indicates a failure to resolve a name or address.
  149.  
  150.   class ResolvError < StandardError; end
  151.  
  152.   ##
  153.   # Indicates a timeout resolving a name or address.
  154.  
  155.   class ResolvTimeout < TimeoutError; end
  156.  
  157.   ##
  158.   # DNS::Hosts is a hostname resolver that uses the system hosts file.
  159.  
  160.   class Hosts
  161.     if /mswin32|mingw|bccwin/ =~ RUBY_PLATFORM
  162.       require 'win32/resolv'
  163.       DefaultFileName = Win32::Resolv.get_hosts_path
  164.     else
  165.       DefaultFileName = '/etc/hosts'
  166.     end
  167.  
  168.     ##
  169.     # Creates a new DNS::Hosts, using +filename+ for its data source.
  170.  
  171.     def initialize(filename = DefaultFileName)
  172.       @filename = filename
  173.       @mutex = Mutex.new
  174.       @initialized = nil
  175.     end
  176.  
  177.     def lazy_initialize # :nodoc:
  178.       @mutex.synchronize {
  179.         unless @initialized
  180.           @name2addr = {}
  181.           @addr2name = {}
  182.           open(@filename) {|f|
  183.             f.each {|line|
  184.               line.sub!(/#.*/, '')
  185.               addr, hostname, *aliases = line.split(/\s+/)
  186.               next unless addr
  187.               addr.untaint
  188.               hostname.untaint
  189.               @addr2name[addr] = [] unless @addr2name.include? addr
  190.               @addr2name[addr] << hostname
  191.               @addr2name[addr] += aliases
  192.               @name2addr[hostname] = [] unless @name2addr.include? hostname
  193.               @name2addr[hostname] << addr
  194.               aliases.each {|n|
  195.                 n.untaint
  196.                 @name2addr[n] = [] unless @name2addr.include? n
  197.                 @name2addr[n] << addr
  198.               }
  199.             }
  200.           }
  201.           @name2addr.each {|name, arr| arr.reverse!}
  202.           @initialized = true
  203.         end
  204.       }
  205.       self
  206.     end
  207.  
  208.     ##
  209.     # Gets the IP address of +name+ from the hosts file.
  210.  
  211.     def getaddress(name)
  212.       each_address(name) {|address| return address}
  213.       raise ResolvError.new("#{@filename} has no name: #{name}")
  214.     end
  215.  
  216.     ##
  217.     # Gets all IP addresses for +name+ from the hosts file.
  218.  
  219.     def getaddresses(name)
  220.       ret = []
  221.       each_address(name) {|address| ret << address}
  222.       return ret
  223.     end
  224.  
  225.     ##
  226.     # Iterates over all IP addresses for +name+ retrieved from the hosts file.
  227.  
  228.     def each_address(name, &proc)
  229.       lazy_initialize
  230.       if @name2addr.include?(name)
  231.         @name2addr[name].each(&proc)
  232.       end
  233.     end
  234.  
  235.     ##
  236.     # Gets the hostname of +address+ from the hosts file.
  237.  
  238.     def getname(address)
  239.       each_name(address) {|name| return name}
  240.       raise ResolvError.new("#{@filename} has no address: #{address}")
  241.     end
  242.  
  243.     ##
  244.     # Gets all hostnames for +address+ from the hosts file.
  245.  
  246.     def getnames(address)
  247.       ret = []
  248.       each_name(address) {|name| ret << name}
  249.       return ret
  250.     end
  251.  
  252.     ##
  253.     # Iterates over all hostnames for +address+ retrieved from the hosts file.
  254.  
  255.     def each_name(address, &proc)
  256.       lazy_initialize
  257.       if @addr2name.include?(address)
  258.         @addr2name[address].each(&proc)
  259.       end
  260.     end
  261.   end
  262.  
  263.   ##
  264.   # Resolv::DNS is a DNS stub resolver.
  265.   #
  266.   # Information taken from the following places:
  267.   #
  268.   # * STD0013
  269.   # * RFC 1035
  270.   # * ftp://ftp.isi.edu/in-notes/iana/assignments/dns-parameters
  271.   # * etc.
  272.  
  273.   class DNS
  274.  
  275.     ##
  276.     # Default DNS Port
  277.  
  278.     Port = 53
  279.  
  280.     ##
  281.     # Default DNS UDP packet size
  282.  
  283.     UDPSize = 512
  284.  
  285.     ##
  286.     # Group of DNS resolver threads (obsolete)
  287.  
  288.     DNSThreadGroup = ThreadGroup.new
  289.  
  290.     ##
  291.     # Creates a new DNS resolver.  See Resolv::DNS.new for argument details.
  292.     #
  293.     # Yields the created DNS resolver to the block, if given, otherwise
  294.     # returns it.
  295.  
  296.     def self.open(*args)
  297.       dns = new(*args)
  298.       return dns unless block_given?
  299.       begin
  300.         yield dns
  301.       ensure
  302.         dns.close
  303.       end
  304.     end
  305.  
  306.     ##
  307.     # Creates a new DNS resolver.
  308.     #
  309.     # +config_info+ can be:
  310.     # 
  311.     # nil:: Uses /etc/resolv.conf.
  312.     # String:: Path to a file using /etc/resolv.conf's format.
  313.     # Hash:: Must contain :nameserver, :search and :ndots keys.
  314.     #
  315.     # Example:
  316.     #
  317.     #   Resolv::DNS.new(:nameserver => ['210.251.121.21'],
  318.     #                   :search => ['ruby-lang.org'],
  319.     #                   :ndots => 1)
  320.  
  321.     def initialize(config_info=nil)
  322.       @mutex = Mutex.new
  323.       @config = Config.new(config_info)
  324.       @initialized = nil
  325.     end
  326.  
  327.     def lazy_initialize # :nodoc:
  328.       @mutex.synchronize {
  329.         unless @initialized
  330.           @config.lazy_initialize
  331.           @initialized = true
  332.         end
  333.       }
  334.       self
  335.     end
  336.  
  337.     ##
  338.     # Closes the DNS resolver.
  339.  
  340.     def close
  341.       @mutex.synchronize {
  342.         if @initialized
  343.           @initialized = false
  344.         end
  345.       }
  346.     end
  347.  
  348.     ##
  349.     # Gets the IP address of +name+ from the DNS resolver.
  350.     #
  351.     # +name+ can be a Resolv::DNS::Name or a String.  Retrieved address will
  352.     # be a Resolv::IPv4 or Resolv::IPv6
  353.  
  354.     def getaddress(name)
  355.       each_address(name) {|address| return address}
  356.       raise ResolvError.new("DNS result has no information for #{name}")
  357.     end
  358.  
  359.     ##
  360.     # Gets all IP addresses for +name+ from the DNS resolver.
  361.     #
  362.     # +name+ can be a Resolv::DNS::Name or a String.  Retrieved addresses will
  363.     # be a Resolv::IPv4 or Resolv::IPv6
  364.  
  365.     def getaddresses(name)
  366.       ret = []
  367.       each_address(name) {|address| ret << address}
  368.       return ret
  369.     end
  370.  
  371.     ##
  372.     # Iterates over all IP addresses for +name+ retrieved from the DNS
  373.     # resolver.
  374.     #
  375.     # +name+ can be a Resolv::DNS::Name or a String.  Retrieved addresses will
  376.     # be a Resolv::IPv4 or Resolv::IPv6
  377.  
  378.     def each_address(name)
  379.       each_resource(name, Resource::IN::A) {|resource| yield resource.address}
  380.       each_resource(name, Resource::IN::AAAA) {|resource| yield resource.address}
  381.     end
  382.  
  383.     ##
  384.     # Gets the hostname for +address+ from the DNS resolver.
  385.     #
  386.     # +address+ must be a Resolv::IPv4, Resolv::IPv6 or a String.  Retrieved
  387.     # name will be a Resolv::DNS::Name.
  388.  
  389.     def getname(address)
  390.       each_name(address) {|name| return name}
  391.       raise ResolvError.new("DNS result has no information for #{address}")
  392.     end
  393.  
  394.     ##
  395.     # Gets all hostnames for +address+ from the DNS resolver.
  396.     #
  397.     # +address+ must be a Resolv::IPv4, Resolv::IPv6 or a String.  Retrieved
  398.     # names will be Resolv::DNS::Name instances.
  399.  
  400.     def getnames(address)
  401.       ret = []
  402.       each_name(address) {|name| ret << name}
  403.       return ret
  404.     end
  405.  
  406.     ##
  407.     # Iterates over all hostnames for +address+ retrieved from the DNS
  408.     # resolver.
  409.     #
  410.     # +address+ must be a Resolv::IPv4, Resolv::IPv6 or a String.  Retrieved
  411.     # names will be Resolv::DNS::Name instances.
  412.  
  413.     def each_name(address)
  414.       case address
  415.       when Name
  416.         ptr = address
  417.       when IPv4::Regex
  418.         ptr = IPv4.create(address).to_name
  419.       when IPv6::Regex
  420.         ptr = IPv6.create(address).to_name
  421.       else
  422.         raise ResolvError.new("cannot interpret as address: #{address}")
  423.       end
  424.       each_resource(ptr, Resource::IN::PTR) {|resource| yield resource.name}
  425.     end
  426.  
  427.     ##
  428.     # Look up the +typeclass+ DNS resource of +name+.
  429.     #
  430.     # +name+ must be a Resolv::DNS::Name or a String.
  431.     #
  432.     # +typeclass+ should be one of the following:
  433.     #
  434.     # * Resolv::DNS::Resource::IN::A
  435.     # * Resolv::DNS::Resource::IN::AAAA
  436.     # * Resolv::DNS::Resource::IN::ANY
  437.     # * Resolv::DNS::Resource::IN::CNAME
  438.     # * Resolv::DNS::Resource::IN::HINFO
  439.     # * Resolv::DNS::Resource::IN::MINFO
  440.     # * Resolv::DNS::Resource::IN::MX
  441.     # * Resolv::DNS::Resource::IN::NS
  442.     # * Resolv::DNS::Resource::IN::PTR
  443.     # * Resolv::DNS::Resource::IN::SOA
  444.     # * Resolv::DNS::Resource::IN::TXT
  445.     # * Resolv::DNS::Resource::IN::WKS
  446.     #
  447.     # Returned resource is represented as a Resolv::DNS::Resource instance,
  448.     # i.e. Resolv::DNS::Resource::IN::A.
  449.  
  450.     def getresource(name, typeclass)
  451.       each_resource(name, typeclass) {|resource| return resource}
  452.       raise ResolvError.new("DNS result has no information for #{name}")
  453.     end
  454.  
  455.     ##
  456.     # Looks up all +typeclass+ DNS resources for +name+.  See #getresource for
  457.     # argument details.
  458.   
  459.     def getresources(name, typeclass)
  460.       ret = []
  461.       each_resource(name, typeclass) {|resource| ret << resource}
  462.       return ret
  463.     end
  464.  
  465.     ##
  466.     # Iterates over all +typeclass+ DNS resources for +name+.  See
  467.     # #getresource for argument details.
  468.   
  469.     def each_resource(name, typeclass, &proc)
  470.       lazy_initialize
  471.       requester = make_requester
  472.       senders = {}
  473.       begin
  474.         @config.resolv(name) {|candidate, tout, nameserver|
  475.           msg = Message.new
  476.           msg.rd = 1
  477.           msg.add_question(candidate, typeclass)
  478.           unless sender = senders[[candidate, nameserver]]
  479.             sender = senders[[candidate, nameserver]] =
  480.               requester.sender(msg, candidate, nameserver)
  481.           end
  482.           reply, reply_name = requester.request(sender, tout)
  483.           case reply.rcode
  484.           when RCode::NoError
  485.             extract_resources(reply, reply_name, typeclass, &proc)
  486.             return
  487.           when RCode::NXDomain
  488.             raise Config::NXDomain.new(reply_name.to_s)
  489.           else
  490.             raise Config::OtherResolvError.new(reply_name.to_s)
  491.           end
  492.         }
  493.       ensure
  494.         requester.close
  495.       end
  496.     end
  497.  
  498.     def make_requester # :nodoc:
  499.       if nameserver = @config.single?
  500.         Requester::ConnectedUDP.new(nameserver)
  501.       else
  502.         Requester::UnconnectedUDP.new
  503.       end
  504.     end
  505.  
  506.     def extract_resources(msg, name, typeclass) # :nodoc:
  507.       if typeclass < Resource::ANY
  508.         n0 = Name.create(name)
  509.         msg.each_answer {|n, ttl, data|
  510.           yield data if n0 == n
  511.         }
  512.       end
  513.       yielded = false
  514.       n0 = Name.create(name)
  515.       msg.each_answer {|n, ttl, data|
  516.         if n0 == n
  517.           case data
  518.           when typeclass
  519.             yield data
  520.             yielded = true
  521.           when Resource::CNAME
  522.             n0 = data.name
  523.           end
  524.         end
  525.       }
  526.       return if yielded
  527.       msg.each_answer {|n, ttl, data|
  528.         if n0 == n
  529.           case data
  530.           when typeclass
  531.             yield data
  532.           end
  533.         end
  534.       }
  535.     end
  536.  
  537.     if defined? SecureRandom
  538.       def self.random(arg) # :nodoc:
  539.         begin
  540.           SecureRandom.random_number(arg)
  541.         rescue NotImplementedError
  542.           rand(arg)
  543.         end
  544.       end
  545.     else
  546.       def self.random(arg) # :nodoc:
  547.         rand(arg)
  548.       end
  549.     end
  550.  
  551.  
  552.     def self.rangerand(range) # :nodoc:
  553.       base = range.begin
  554.       len = range.end - range.begin
  555.       if !range.exclude_end?
  556.         len += 1
  557.       end
  558.       base + random(len)
  559.     end
  560.  
  561.     RequestID = {}
  562.     RequestIDMutex = Mutex.new
  563.  
  564.     def self.allocate_request_id(host, port) # :nodoc:
  565.       id = nil
  566.       RequestIDMutex.synchronize {
  567.         h = (RequestID[[host, port]] ||= {})
  568.         begin
  569.           id = rangerand(0x0000..0xffff)
  570.         end while h[id] 
  571.         h[id] = true
  572.       }
  573.       id
  574.     end
  575.  
  576.     def self.free_request_id(host, port, id) # :nodoc:
  577.       RequestIDMutex.synchronize {
  578.         key = [host, port]
  579.         if h = RequestID[key]
  580.           h.delete id
  581.           if h.empty?
  582.             RequestID.delete key
  583.           end
  584.         end
  585.       }
  586.     end
  587.  
  588.     def self.bind_random_port(udpsock) # :nodoc:
  589.       begin
  590.         port = rangerand(1024..65535)
  591.         udpsock.bind("", port)
  592.       rescue Errno::EADDRINUSE
  593.         retry
  594.       end
  595.     end
  596.  
  597.     class Requester # :nodoc:
  598.       def initialize
  599.         @senders = {}
  600.         @sock = nil
  601.       end
  602.  
  603.       def request(sender, tout)
  604.         timelimit = Time.now + tout
  605.         sender.send
  606.         while (now = Time.now) < timelimit
  607.           timeout = timelimit - now
  608.           if !IO.select([@sock], nil, nil, timeout)
  609.             raise ResolvTimeout
  610.           end
  611.           reply, from = recv_reply
  612.           begin
  613.             msg = Message.decode(reply)
  614.           rescue DecodeError
  615.             next # broken DNS message ignored
  616.           end
  617.           if s = @senders[[from,msg.id]]
  618.             break
  619.           else
  620.             # unexpected DNS message ignored
  621.           end
  622.         end
  623.         return msg, s.data
  624.       end
  625.  
  626.       def close
  627.         sock = @sock
  628.         @sock = nil
  629.         sock.close if sock
  630.       end
  631.  
  632.       class Sender # :nodoc:
  633.         def initialize(msg, data, sock)
  634.           @msg = msg
  635.           @data = data
  636.           @sock = sock
  637.         end
  638.       end
  639.  
  640.       class UnconnectedUDP < Requester # :nodoc:
  641.         def initialize
  642.           super()
  643.           @sock = UDPSocket.new
  644.           @sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::F_SETFD
  645.           DNS.bind_random_port(@sock)
  646.         end
  647.  
  648.         def recv_reply
  649.           reply, from = @sock.recvfrom(UDPSize)
  650.           return reply, [from[3],from[1]]
  651.         end
  652.  
  653.         def sender(msg, data, host, port=Port)
  654.           service = [host, port]
  655.           id = DNS.allocate_request_id(host, port)
  656.           request = msg.encode
  657.           request[0,2] = [id].pack('n')
  658.           return @senders[[service, id]] =
  659.             Sender.new(request, data, @sock, host, port)
  660.         end
  661.  
  662.         def close
  663.           super
  664.           @senders.each_key {|service, id|
  665.             DNS.free_request_id(service[0], service[1], id)
  666.           }
  667.         end
  668.  
  669.         class Sender < Requester::Sender # :nodoc:
  670.           def initialize(msg, data, sock, host, port)
  671.             super(msg, data, sock)
  672.             @host = host
  673.             @port = port
  674.           end
  675.           attr_reader :data
  676.  
  677.           def send
  678.             @sock.send(@msg, 0, @host, @port)
  679.           end
  680.         end
  681.       end
  682.  
  683.       class ConnectedUDP < Requester # :nodoc:
  684.         def initialize(host, port=Port)
  685.           super()
  686.           @host = host
  687.           @port = port
  688.           @sock = UDPSocket.new(host.index(':') ? Socket::AF_INET6 : Socket::AF_INET)
  689.           DNS.bind_random_port(@sock)
  690.           @sock.connect(host, port)
  691.           @sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::F_SETFD
  692.         end
  693.  
  694.         def recv_reply
  695.           reply = @sock.recv(UDPSize)
  696.           return reply, nil
  697.         end
  698.  
  699.         def sender(msg, data, host=@host, port=@port)
  700.           unless host == @host && port == @port
  701.             raise RequestError.new("host/port don't match: #{host}:#{port}")
  702.           end
  703.           id = DNS.allocate_request_id(@host, @port)
  704.           request = msg.encode
  705.           request[0,2] = [id].pack('n')
  706.           return @senders[[nil,id]] = Sender.new(request, data, @sock)
  707.         end
  708.  
  709.         def close
  710.           super
  711.           @senders.each_key {|from, id|
  712.             DNS.free_request_id(@host, @port, id)
  713.           }
  714.         end
  715.  
  716.         class Sender < Requester::Sender # :nodoc:
  717.           def send
  718.             @sock.send(@msg, 0)
  719.           end
  720.           attr_reader :data
  721.         end
  722.       end
  723.  
  724.       class TCP < Requester # :nodoc:
  725.         def initialize(host, port=Port)
  726.           super()
  727.           @host = host
  728.           @port = port
  729.           @sock = TCPSocket.new(@host, @port)
  730.           @sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::F_SETFD
  731.           @senders = {}
  732.         end
  733.  
  734.         def recv_reply
  735.           len = @sock.read(2).unpack('n')[0]
  736.           reply = @sock.read(len)
  737.           return reply, nil
  738.         end
  739.  
  740.         def sender(msg, data, host=@host, port=@port)
  741.           unless host == @host && port == @port
  742.             raise RequestError.new("host/port don't match: #{host}:#{port}")
  743.           end
  744.           id = DNS.allocate_request_id(@host, @port)
  745.           request = msg.encode
  746.           request[0,2] = [request.length, id].pack('nn')
  747.           return @senders[[nil,id]] = Sender.new(request, data, @sock)
  748.         end
  749.  
  750.         class Sender < Requester::Sender # :nodoc:
  751.           def send
  752.             @sock.print(@msg)
  753.             @sock.flush
  754.           end
  755.           attr_reader :data
  756.         end
  757.  
  758.         def close
  759.           super
  760.           @senders.each_key {|from,id|
  761.             DNS.free_request_id(@host, @port, id)
  762.           }
  763.         end
  764.       end
  765.  
  766.       ##
  767.       # Indicates a problem with the DNS request.
  768.  
  769.       class RequestError < StandardError
  770.       end
  771.     end
  772.  
  773.     class Config # :nodoc:
  774.       def initialize(config_info=nil)
  775.         @mutex = Mutex.new
  776.         @config_info = config_info
  777.         @initialized = nil
  778.       end
  779.  
  780.       def Config.parse_resolv_conf(filename)
  781.         nameserver = []
  782.         search = nil
  783.         ndots = 1
  784.         open(filename) {|f|
  785.           f.each {|line|
  786.             line.sub!(/[#;].*/, '')
  787.             keyword, *args = line.split(/\s+/)
  788.             args.each { |arg|
  789.               arg.untaint
  790.             }
  791.             next unless keyword
  792.             case keyword
  793.             when 'nameserver'
  794.               nameserver += args
  795.             when 'domain'
  796.               next if args.empty?
  797.               search = [args[0]]
  798.             when 'search'
  799.               next if args.empty?
  800.               search = args
  801.             when 'options'
  802.               args.each {|arg|
  803.                 case arg
  804.                 when /\Andots:(\d+)\z/
  805.                   ndots = $1.to_i
  806.                 end
  807.               }
  808.             end
  809.           }
  810.         }
  811.         return { :nameserver => nameserver, :search => search, :ndots => ndots }
  812.       end
  813.  
  814.       def Config.default_config_hash(filename="/etc/resolv.conf")
  815.         if File.exist? filename
  816.           config_hash = Config.parse_resolv_conf(filename)
  817.         else
  818.           if /mswin32|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM
  819.             require 'win32/resolv'
  820.             search, nameserver = Win32::Resolv.get_resolv_info
  821.             config_hash = {}
  822.             config_hash[:nameserver] = nameserver if nameserver
  823.             config_hash[:search] = [search].flatten if search
  824.           end
  825.         end
  826.         config_hash
  827.       end
  828.  
  829.       def lazy_initialize
  830.         @mutex.synchronize {
  831.           unless @initialized
  832.             @nameserver = []
  833.             @search = nil
  834.             @ndots = 1
  835.             case @config_info
  836.             when nil
  837.               config_hash = Config.default_config_hash
  838.             when String
  839.               config_hash = Config.parse_resolv_conf(@config_info)
  840.             when Hash
  841.               config_hash = @config_info.dup
  842.               if String === config_hash[:nameserver]
  843.                 config_hash[:nameserver] = [config_hash[:nameserver]]
  844.               end
  845.               if String === config_hash[:search]
  846.                 config_hash[:search] = [config_hash[:search]]
  847.               end
  848.             else
  849.               raise ArgumentError.new("invalid resolv configuration: #{@config_info.inspect}")
  850.             end
  851.             @nameserver = config_hash[:nameserver] if config_hash.include? :nameserver
  852.             @search = config_hash[:search] if config_hash.include? :search
  853.             @ndots = config_hash[:ndots] if config_hash.include? :ndots
  854.  
  855.             @nameserver = ['0.0.0.0'] if @nameserver.empty?
  856.             if @search
  857.               @search = @search.map {|arg| Label.split(arg) }
  858.             else
  859.               hostname = Socket.gethostname
  860.               if /\./ =~ hostname
  861.                 @search = [Label.split($')]
  862.               else
  863.                 @search = [[]]
  864.               end
  865.             end
  866.  
  867.             if !@nameserver.kind_of?(Array) ||
  868.                !@nameserver.all? {|ns| String === ns }
  869.               raise ArgumentError.new("invalid nameserver config: #{@nameserver.inspect}")
  870.             end
  871.  
  872.             if !@search.kind_of?(Array) ||
  873.                !@search.all? {|ls| ls.all? {|l| Label::Str === l } }
  874.               raise ArgumentError.new("invalid search config: #{@search.inspect}")
  875.             end
  876.  
  877.             if !@ndots.kind_of?(Integer)
  878.               raise ArgumentError.new("invalid ndots config: #{@ndots.inspect}")
  879.             end
  880.  
  881.             @initialized = true
  882.           end
  883.         }
  884.         self
  885.       end
  886.  
  887.       def single?
  888.         lazy_initialize
  889.         if @nameserver.length == 1
  890.           return @nameserver[0]
  891.         else
  892.           return nil
  893.         end
  894.       end
  895.  
  896.       def generate_candidates(name)
  897.         candidates = nil
  898.         name = Name.create(name)
  899.         if name.absolute?
  900.           candidates = [name]
  901.         else
  902.           if @ndots <= name.length - 1
  903.             candidates = [Name.new(name.to_a)]
  904.           else
  905.             candidates = []
  906.           end
  907.           candidates.concat(@search.map {|domain| Name.new(name.to_a + domain)})
  908.         end
  909.         return candidates
  910.       end
  911.  
  912.       InitialTimeout = 5
  913.  
  914.       def generate_timeouts
  915.         ts = [InitialTimeout]
  916.         ts << ts[-1] * 2 / @nameserver.length
  917.         ts << ts[-1] * 2
  918.         ts << ts[-1] * 2
  919.         return ts
  920.       end
  921.  
  922.       def resolv(name)
  923.         candidates = generate_candidates(name)
  924.         timeouts = generate_timeouts
  925.         begin
  926.           candidates.each {|candidate|
  927.             begin
  928.               timeouts.each {|tout|
  929.                 @nameserver.each {|nameserver|
  930.                   begin
  931.                     yield candidate, tout, nameserver
  932.                   rescue ResolvTimeout
  933.                   end
  934.                 }
  935.               }
  936.               raise ResolvError.new("DNS resolv timeout: #{name}")
  937.             rescue NXDomain
  938.             end
  939.           }
  940.         rescue ResolvError
  941.         end
  942.       end
  943.  
  944.       ##
  945.       # Indicates no such domain was found.
  946.  
  947.       class NXDomain < ResolvError
  948.       end
  949.  
  950.       ##
  951.       # Indicates some other unhandled resolver error was encountered.
  952.  
  953.       class OtherResolvError < ResolvError
  954.       end
  955.     end
  956.  
  957.     module OpCode # :nodoc:
  958.       Query = 0
  959.       IQuery = 1
  960.       Status = 2
  961.       Notify = 4
  962.       Update = 5
  963.     end
  964.  
  965.     module RCode # :nodoc:
  966.       NoError = 0
  967.       FormErr = 1
  968.       ServFail = 2
  969.       NXDomain = 3
  970.       NotImp = 4
  971.       Refused = 5
  972.       YXDomain = 6
  973.       YXRRSet = 7
  974.       NXRRSet = 8
  975.       NotAuth = 9
  976.       NotZone = 10
  977.       BADVERS = 16
  978.       BADSIG = 16
  979.       BADKEY = 17
  980.       BADTIME = 18
  981.       BADMODE = 19
  982.       BADNAME = 20
  983.       BADALG = 21
  984.     end
  985.  
  986.     ##
  987.     # Indicates that the DNS response was unable to be decoded.
  988.  
  989.     class DecodeError < StandardError
  990.     end
  991.  
  992.     ##
  993.     # Indicates that the DNS request was unable to be encoded.
  994.  
  995.     class EncodeError < StandardError
  996.     end
  997.  
  998.     module Label # :nodoc:
  999.       def self.split(arg)
  1000.         labels = []
  1001.         arg.scan(/[^\.]+/) {labels << Str.new($&)}
  1002.         return labels
  1003.       end
  1004.  
  1005.       class Str # :nodoc:
  1006.         def initialize(string)
  1007.           @string = string
  1008.           @downcase = string.downcase
  1009.         end
  1010.         attr_reader :string, :downcase
  1011.  
  1012.         def to_s
  1013.           return @string
  1014.         end
  1015.  
  1016.         def inspect
  1017.           return "#<#{self.class} #{self.to_s}>"
  1018.         end
  1019.  
  1020.         def ==(other)
  1021.           return @downcase == other.downcase
  1022.         end
  1023.  
  1024.         def eql?(other)
  1025.           return self == other
  1026.         end
  1027.  
  1028.         def hash
  1029.           return @downcase.hash
  1030.         end
  1031.       end
  1032.     end
  1033.  
  1034.     ##
  1035.     # A representation of a DNS name.
  1036.  
  1037.     class Name
  1038.       
  1039.       ##
  1040.       # Creates a new DNS name from +arg+.  +arg+ can be:
  1041.       #
  1042.       # Name:: returns +arg+.
  1043.       # String:: Creates a new Name.
  1044.  
  1045.       def self.create(arg)
  1046.         case arg
  1047.         when Name
  1048.           return arg
  1049.         when String
  1050.           return Name.new(Label.split(arg), /\.\z/ =~ arg ? true : false)
  1051.         else
  1052.           raise ArgumentError.new("cannot interpret as DNS name: #{arg.inspect}")
  1053.         end
  1054.       end
  1055.  
  1056.       def initialize(labels, absolute=true) # :nodoc:
  1057.         @labels = labels
  1058.         @absolute = absolute
  1059.       end
  1060.  
  1061.       def inspect # :nodoc:
  1062.         "#<#{self.class}: #{self.to_s}#{@absolute ? '.' : ''}>"
  1063.       end
  1064.  
  1065.       ##
  1066.       # True if this name is absolute.
  1067.  
  1068.       def absolute?
  1069.         return @absolute
  1070.       end
  1071.  
  1072.       def ==(other) # :nodoc:
  1073.         return false unless Name === other
  1074.         return @labels.join == other.to_a.join && @absolute == other.absolute?
  1075.       end
  1076.  
  1077.       alias eql? == # :nodoc:
  1078.  
  1079.       ##
  1080.       # Returns true if +other+ is a subdomain.
  1081.       #
  1082.       # Example:
  1083.       #
  1084.       #   domain = Resolv::DNS::Name.create("y.z")
  1085.       #   p Resolv::DNS::Name.create("w.x.y.z").subdomain_of?(domain) #=> true
  1086.       #   p Resolv::DNS::Name.create("x.y.z").subdomain_of?(domain) #=> true
  1087.       #   p Resolv::DNS::Name.create("y.z").subdomain_of?(domain) #=> false
  1088.       #   p Resolv::DNS::Name.create("z").subdomain_of?(domain) #=> false
  1089.       #   p Resolv::DNS::Name.create("x.y.z.").subdomain_of?(domain) #=> false
  1090.       #   p Resolv::DNS::Name.create("w.z").subdomain_of?(domain) #=> false
  1091.       #
  1092.  
  1093.       def subdomain_of?(other)
  1094.         raise ArgumentError, "not a domain name: #{other.inspect}" unless Name === other
  1095.         return false if @absolute != other.absolute?
  1096.         other_len = other.length
  1097.         return false if @labels.length <= other_len
  1098.         return @labels[-other_len, other_len] == other.to_a
  1099.       end
  1100.  
  1101.       def hash # :nodoc:
  1102.         return @labels.hash ^ @absolute.hash
  1103.       end
  1104.  
  1105.       def to_a # :nodoc:
  1106.         return @labels
  1107.       end
  1108.  
  1109.       def length # :nodoc:
  1110.         return @labels.length
  1111.       end
  1112.  
  1113.       def [](i) # :nodoc:
  1114.         return @labels[i]
  1115.       end
  1116.  
  1117.       ##
  1118.       # returns the domain name as a string.
  1119.       #
  1120.       # The domain name doesn't have a trailing dot even if the name object is
  1121.       # absolute.
  1122.       #
  1123.       # Example:
  1124.       #
  1125.       #   p Resolv::DNS::Name.create("x.y.z.").to_s #=> "x.y.z"
  1126.       #   p Resolv::DNS::Name.create("x.y.z").to_s #=> "x.y.z"
  1127.  
  1128.       def to_s
  1129.         return @labels.join('.')
  1130.       end
  1131.     end
  1132.  
  1133.     class Message # :nodoc:
  1134.       @@identifier = -1
  1135.  
  1136.       def initialize(id = (@@identifier += 1) & 0xffff)
  1137.         @id = id
  1138.         @qr = 0
  1139.         @opcode = 0
  1140.         @aa = 0
  1141.         @tc = 0
  1142.         @rd = 0 # recursion desired
  1143.         @ra = 0 # recursion available
  1144.         @rcode = 0
  1145.         @question = []
  1146.         @answer = []
  1147.         @authority = []
  1148.         @additional = []
  1149.       end
  1150.  
  1151.       attr_accessor :id, :qr, :opcode, :aa, :tc, :rd, :ra, :rcode
  1152.       attr_reader :question, :answer, :authority, :additional
  1153.  
  1154.       def ==(other)
  1155.         return @id == other.id &&
  1156.                @qr == other.qr &&
  1157.                @opcode == other.opcode &&
  1158.                @aa == other.aa &&
  1159.                @tc == other.tc &&
  1160.                @rd == other.rd &&
  1161.                @ra == other.ra &&
  1162.                @rcode == other.rcode &&
  1163.                @question == other.question &&
  1164.                @answer == other.answer &&
  1165.                @authority == other.authority &&
  1166.                @additional == other.additional
  1167.       end
  1168.  
  1169.       def add_question(name, typeclass)
  1170.         @question << [Name.create(name), typeclass]
  1171.       end
  1172.  
  1173.       def each_question
  1174.         @question.each {|name, typeclass|
  1175.           yield name, typeclass
  1176.         }
  1177.       end
  1178.  
  1179.       def add_answer(name, ttl, data)
  1180.         @answer << [Name.create(name), ttl, data]
  1181.       end
  1182.  
  1183.       def each_answer
  1184.         @answer.each {|name, ttl, data|
  1185.           yield name, ttl, data
  1186.         }
  1187.       end
  1188.  
  1189.       def add_authority(name, ttl, data)
  1190.         @authority << [Name.create(name), ttl, data]
  1191.       end
  1192.  
  1193.       def each_authority
  1194.         @authority.each {|name, ttl, data|
  1195.           yield name, ttl, data
  1196.         }
  1197.       end
  1198.  
  1199.       def add_additional(name, ttl, data)
  1200.         @additional << [Name.create(name), ttl, data]
  1201.       end
  1202.  
  1203.       def each_additional
  1204.         @additional.each {|name, ttl, data|
  1205.           yield name, ttl, data
  1206.         }
  1207.       end
  1208.  
  1209.       def each_resource
  1210.         each_answer {|name, ttl, data| yield name, ttl, data}
  1211.         each_authority {|name, ttl, data| yield name, ttl, data}
  1212.         each_additional {|name, ttl, data| yield name, ttl, data}
  1213.       end
  1214.  
  1215.       def encode
  1216.         return MessageEncoder.new {|msg|
  1217.           msg.put_pack('nnnnnn',
  1218.             @id,
  1219.             (@qr & 1) << 15 |
  1220.             (@opcode & 15) << 11 |
  1221.             (@aa & 1) << 10 |
  1222.             (@tc & 1) << 9 |
  1223.             (@rd & 1) << 8 |
  1224.             (@ra & 1) << 7 |
  1225.             (@rcode & 15),
  1226.             @question.length,
  1227.             @answer.length,
  1228.             @authority.length,
  1229.             @additional.length)
  1230.           @question.each {|q|
  1231.             name, typeclass = q
  1232.             msg.put_name(name)
  1233.             msg.put_pack('nn', typeclass::TypeValue, typeclass::ClassValue)
  1234.           }
  1235.           [@answer, @authority, @additional].each {|rr|
  1236.             rr.each {|r|
  1237.               name, ttl, data = r
  1238.               msg.put_name(name)
  1239.               msg.put_pack('nnN', data.class::TypeValue, data.class::ClassValue, ttl)
  1240.               msg.put_length16 {data.encode_rdata(msg)}
  1241.             }
  1242.           }
  1243.         }.to_s
  1244.       end
  1245.  
  1246.       class MessageEncoder # :nodoc:
  1247.         def initialize
  1248.           @data = ''
  1249.           @names = {}
  1250.           yield self
  1251.         end
  1252.  
  1253.         def to_s
  1254.           return @data
  1255.         end
  1256.  
  1257.         def put_bytes(d)
  1258.           @data << d
  1259.         end
  1260.  
  1261.         def put_pack(template, *d)
  1262.           @data << d.pack(template)
  1263.         end
  1264.  
  1265.         def put_length16
  1266.           length_index = @data.length
  1267.           @data << "\0\0"
  1268.           data_start = @data.length
  1269.           yield
  1270.           data_end = @data.length
  1271.           @data[length_index, 2] = [data_end - data_start].pack("n")
  1272.         end
  1273.  
  1274.         def put_string(d)
  1275.           self.put_pack("C", d.length)
  1276.           @data << d
  1277.         end
  1278.  
  1279.         def put_string_list(ds)
  1280.           ds.each {|d|
  1281.             self.put_string(d)
  1282.           }
  1283.         end
  1284.  
  1285.         def put_name(d)
  1286.           put_labels(d.to_a)
  1287.         end
  1288.  
  1289.         def put_labels(d)
  1290.           d.each_index {|i|
  1291.             domain = d[i..-1]
  1292.             if idx = @names[domain]
  1293.               self.put_pack("n", 0xc000 | idx)
  1294.               return
  1295.             else
  1296.               @names[domain] = @data.length
  1297.               self.put_label(d[i])
  1298.             end
  1299.           }
  1300.           @data << "\0"
  1301.         end
  1302.  
  1303.         def put_label(d)
  1304.           self.put_string(d.to_s)
  1305.         end
  1306.       end
  1307.  
  1308.       def Message.decode(m)
  1309.         o = Message.new(0)
  1310.         MessageDecoder.new(m) {|msg|
  1311.           id, flag, qdcount, ancount, nscount, arcount =
  1312.             msg.get_unpack('nnnnnn')
  1313.           o.id = id
  1314.           o.qr = (flag >> 15) & 1
  1315.           o.opcode = (flag >> 11) & 15
  1316.           o.aa = (flag >> 10) & 1
  1317.           o.tc = (flag >> 9) & 1
  1318.           o.rd = (flag >> 8) & 1
  1319.           o.ra = (flag >> 7) & 1
  1320.           o.rcode = flag & 15
  1321.           (1..qdcount).each {
  1322.             name, typeclass = msg.get_question
  1323.             o.add_question(name, typeclass)
  1324.           }
  1325.           (1..ancount).each {
  1326.             name, ttl, data = msg.get_rr
  1327.             o.add_answer(name, ttl, data)
  1328.           }
  1329.           (1..nscount).each {
  1330.             name, ttl, data = msg.get_rr
  1331.             o.add_authority(name, ttl, data)
  1332.           }
  1333.           (1..arcount).each {
  1334.             name, ttl, data = msg.get_rr
  1335.             o.add_additional(name, ttl, data)
  1336.           }
  1337.         }
  1338.         return o
  1339.       end
  1340.  
  1341.       class MessageDecoder # :nodoc:
  1342.         def initialize(data)
  1343.           @data = data
  1344.           @index = 0
  1345.           @limit = data.length
  1346.           yield self
  1347.         end
  1348.  
  1349.         def get_length16
  1350.           len, = self.get_unpack('n')
  1351.           save_limit = @limit
  1352.           @limit = @index + len
  1353.           d = yield(len)
  1354.           if @index < @limit
  1355.             raise DecodeError.new("junk exists")
  1356.           elsif @limit < @index
  1357.             raise DecodeError.new("limit exceeded")
  1358.           end
  1359.           @limit = save_limit
  1360.           return d
  1361.         end
  1362.  
  1363.         def get_bytes(len = @limit - @index)
  1364.           d = @data[@index, len]
  1365.           @index += len
  1366.           return d
  1367.         end
  1368.  
  1369.         def get_unpack(template)
  1370.           len = 0
  1371.           template.each_byte {|byte|
  1372.             case byte
  1373.             when ?c, ?C
  1374.               len += 1
  1375.             when ?n
  1376.               len += 2
  1377.             when ?N
  1378.               len += 4
  1379.             else
  1380.               raise StandardError.new("unsupported template: '#{byte.chr}' in '#{template}'")
  1381.             end
  1382.           }
  1383.           raise DecodeError.new("limit exceeded") if @limit < @index + len
  1384.           arr = @data.unpack("@#{@index}#{template}")
  1385.           @index += len
  1386.           return arr
  1387.         end
  1388.  
  1389.         def get_string
  1390.           len = @data[@index]
  1391.           raise DecodeError.new("limit exceeded") if @limit < @index + 1 + len
  1392.           d = @data[@index + 1, len]
  1393.           @index += 1 + len
  1394.           return d
  1395.         end
  1396.  
  1397.         def get_string_list
  1398.           strings = []
  1399.           while @index < @limit
  1400.             strings << self.get_string
  1401.           end
  1402.           strings
  1403.         end
  1404.  
  1405.         def get_name
  1406.           return Name.new(self.get_labels)
  1407.         end
  1408.  
  1409.         def get_labels(limit=nil)
  1410.           limit = @index if !limit || @index < limit
  1411.           d = []
  1412.           while true
  1413.             case @data[@index]
  1414.             when 0
  1415.               @index += 1
  1416.               return d
  1417.             when 192..255
  1418.               idx = self.get_unpack('n')[0] & 0x3fff
  1419.               if limit <= idx
  1420.                 raise DecodeError.new("non-backward name pointer")
  1421.               end
  1422.               save_index = @index
  1423.               @index = idx
  1424.               d += self.get_labels(limit)
  1425.               @index = save_index
  1426.               return d
  1427.             else
  1428.               d << self.get_label
  1429.             end
  1430.           end
  1431.           return d
  1432.         end
  1433.  
  1434.         def get_label
  1435.           return Label::Str.new(self.get_string)
  1436.         end
  1437.  
  1438.         def get_question
  1439.           name = self.get_name
  1440.           type, klass = self.get_unpack("nn")
  1441.           return name, Resource.get_class(type, klass)
  1442.         end
  1443.  
  1444.         def get_rr
  1445.           name = self.get_name
  1446.           type, klass, ttl = self.get_unpack('nnN')
  1447.           typeclass = Resource.get_class(type, klass)
  1448.           return name, ttl, self.get_length16 {typeclass.decode_rdata(self)}
  1449.         end
  1450.       end
  1451.     end
  1452.  
  1453.     ##
  1454.     # A DNS query abstract class.
  1455.  
  1456.     class Query
  1457.       def encode_rdata(msg) # :nodoc:
  1458.         raise EncodeError.new("#{self.class} is query.") 
  1459.       end
  1460.  
  1461.       def self.decode_rdata(msg) # :nodoc:
  1462.         raise DecodeError.new("#{self.class} is query.") 
  1463.       end
  1464.     end
  1465.  
  1466.     ##
  1467.     # A DNS resource abstract class.
  1468.  
  1469.     class Resource < Query
  1470.  
  1471.       ##
  1472.       # Remaining Time To Live for this Resource.
  1473.  
  1474.       attr_reader :ttl
  1475.  
  1476.       ClassHash = {} # :nodoc:
  1477.  
  1478.       def encode_rdata(msg) # :nodoc:
  1479.         raise NotImplementedError.new
  1480.       end
  1481.  
  1482.       def self.decode_rdata(msg) # :nodoc:
  1483.         raise NotImplementedError.new
  1484.       end
  1485.  
  1486.       def ==(other) # :nodoc:
  1487.         return self.class == other.class &&
  1488.           self.instance_variables == other.instance_variables &&
  1489.           self.instance_variables.collect {|name| self.instance_eval name} ==
  1490.             other.instance_variables.collect {|name| other.instance_eval name}
  1491.       end
  1492.  
  1493.       def eql?(other) # :nodoc:
  1494.         return self == other
  1495.       end
  1496.  
  1497.       def hash # :nodoc:
  1498.         h = 0
  1499.         self.instance_variables.each {|name|
  1500.           h ^= self.instance_eval("#{name}.hash")
  1501.         }
  1502.         return h
  1503.       end
  1504.  
  1505.       def self.get_class(type_value, class_value) # :nodoc:
  1506.         return ClassHash[[type_value, class_value]] ||
  1507.                Generic.create(type_value, class_value)
  1508.       end
  1509.  
  1510.       ##
  1511.       # A generic resource abstract class.
  1512.  
  1513.       class Generic < Resource
  1514.  
  1515.         ##
  1516.         # Creates a new generic resource.
  1517.  
  1518.         def initialize(data)
  1519.           @data = data
  1520.         end
  1521.  
  1522.         ##
  1523.         # Data for this generic resource.
  1524.  
  1525.         attr_reader :data
  1526.  
  1527.         def encode_rdata(msg) # :nodoc:
  1528.           msg.put_bytes(data)
  1529.         end
  1530.  
  1531.         def self.decode_rdata(msg) # :nodoc:
  1532.           return self.new(msg.get_bytes)
  1533.         end
  1534.  
  1535.         def self.create(type_value, class_value) # :nodoc:
  1536.           c = Class.new(Generic)
  1537.           c.const_set(:TypeValue, type_value)
  1538.           c.const_set(:ClassValue, class_value)
  1539.           Generic.const_set("Type#{type_value}_Class#{class_value}", c)
  1540.           ClassHash[[type_value, class_value]] = c
  1541.           return c
  1542.         end
  1543.       end
  1544.  
  1545.       ##
  1546.       # Domain Name resource abstract class.
  1547.  
  1548.       class DomainName < Resource
  1549.  
  1550.         ##
  1551.         # Creates a new DomainName from +name+.
  1552.  
  1553.         def initialize(name)
  1554.           @name = name
  1555.         end
  1556.  
  1557.         ##
  1558.         # The name of this DomainName.
  1559.  
  1560.         attr_reader :name
  1561.  
  1562.         def encode_rdata(msg) # :nodoc:
  1563.           msg.put_name(@name)
  1564.         end
  1565.  
  1566.         def self.decode_rdata(msg) # :nodoc:
  1567.           return self.new(msg.get_name)
  1568.         end
  1569.       end
  1570.  
  1571.       # Standard (class generic) RRs
  1572.  
  1573.       ClassValue = nil # :nodoc:
  1574.  
  1575.       ##
  1576.       # An authoritative name server.
  1577.  
  1578.       class NS < DomainName
  1579.         TypeValue = 2 # :nodoc:
  1580.       end
  1581.  
  1582.       ##
  1583.       # The canonical name for an alias.
  1584.  
  1585.       class CNAME < DomainName
  1586.         TypeValue = 5 # :nodoc:
  1587.       end
  1588.  
  1589.       ##
  1590.       # Start Of Authority resource.
  1591.  
  1592.       class SOA < Resource
  1593.  
  1594.         TypeValue = 6 # :nodoc:
  1595.  
  1596.         ##
  1597.         # Creates a new SOA record.  See the attr documentation for the
  1598.         # details of each argument.
  1599.  
  1600.         def initialize(mname, rname, serial, refresh, retry_, expire, minimum)
  1601.           @mname = mname
  1602.           @rname = rname
  1603.           @serial = serial
  1604.           @refresh = refresh
  1605.           @retry = retry_
  1606.           @expire = expire
  1607.           @minimum = minimum
  1608.         end
  1609.  
  1610.         ##
  1611.         # Name of the host where the master zone file for this zone resides.
  1612.  
  1613.         attr_reader :mname
  1614.  
  1615.         ##
  1616.         # The person responsible for this domain name.
  1617.  
  1618.         attr_reader :rname
  1619.  
  1620.         ##
  1621.         # The version number of the zone file.
  1622.  
  1623.         attr_reader :serial
  1624.  
  1625.         ##
  1626.         # How often, in seconds, a secondary name server is to check for
  1627.         # updates from the primary name server.
  1628.  
  1629.         attr_reader :refresh
  1630.  
  1631.         ##
  1632.         # How often, in seconds, a secondary name server is to retry after a
  1633.         # failure to check for a refresh.
  1634.  
  1635.         attr_reader :retry
  1636.  
  1637.         ##
  1638.         # Time in seconds that a secondary name server is to use the data
  1639.         # before refreshing from the primary name server.
  1640.  
  1641.         attr_reader :expire
  1642.  
  1643.         ##
  1644.         # The minimum number of seconds to be used for TTL values in RRs.
  1645.  
  1646.         attr_reader :minimum
  1647.  
  1648.         def encode_rdata(msg) # :nodoc:
  1649.           msg.put_name(@mname)
  1650.           msg.put_name(@rname)
  1651.           msg.put_pack('NNNNN', @serial, @refresh, @retry, @expire, @minimum)
  1652.         end
  1653.  
  1654.         def self.decode_rdata(msg) # :nodoc:
  1655.           mname = msg.get_name
  1656.           rname = msg.get_name
  1657.           serial, refresh, retry_, expire, minimum = msg.get_unpack('NNNNN')
  1658.           return self.new(
  1659.             mname, rname, serial, refresh, retry_, expire, minimum)
  1660.         end
  1661.       end
  1662.  
  1663.       ##
  1664.       # A Pointer to another DNS name.
  1665.  
  1666.       class PTR < DomainName
  1667.         TypeValue = 12 # :nodoc:
  1668.       end
  1669.  
  1670.       ##
  1671.       # Host Information resource.
  1672.  
  1673.       class HINFO < Resource
  1674.  
  1675.         TypeValue = 13 # :nodoc:
  1676.  
  1677.         ##
  1678.         # Creates a new HINFO running +os+ on +cpu+.
  1679.  
  1680.         def initialize(cpu, os)
  1681.           @cpu = cpu
  1682.           @os = os
  1683.         end
  1684.  
  1685.         ##
  1686.         # CPU architecture for this resource.
  1687.  
  1688.         attr_reader :cpu
  1689.  
  1690.         ##
  1691.         # Operating system for this resource.
  1692.  
  1693.         attr_reader :os
  1694.  
  1695.         def encode_rdata(msg) # :nodoc:
  1696.           msg.put_string(@cpu)
  1697.           msg.put_string(@os)
  1698.         end
  1699.  
  1700.         def self.decode_rdata(msg) # :nodoc:
  1701.           cpu = msg.get_string
  1702.           os = msg.get_string
  1703.           return self.new(cpu, os)
  1704.         end
  1705.       end
  1706.  
  1707.       ##
  1708.       # Mailing list or mailbox information.
  1709.  
  1710.       class MINFO < Resource
  1711.  
  1712.         TypeValue = 14 # :nodoc:
  1713.  
  1714.         def initialize(rmailbx, emailbx)
  1715.           @rmailbx = rmailbx
  1716.           @emailbx = emailbx
  1717.         end
  1718.  
  1719.         ##
  1720.         # Domain name responsible for this mail list or mailbox.
  1721.  
  1722.         attr_reader :rmailbx
  1723.  
  1724.         ##
  1725.         # Mailbox to use for error messages related to the mail list or mailbox.
  1726.  
  1727.         attr_reader :emailbx
  1728.  
  1729.         def encode_rdata(msg) # :nodoc:
  1730.           msg.put_name(@rmailbx)
  1731.           msg.put_name(@emailbx)
  1732.         end
  1733.  
  1734.         def self.decode_rdata(msg) # :nodoc:
  1735.           rmailbx = msg.get_string
  1736.           emailbx = msg.get_string
  1737.           return self.new(rmailbx, emailbx)
  1738.         end
  1739.       end
  1740.  
  1741.       ##
  1742.       # Mail Exchanger resource.
  1743.  
  1744.       class MX < Resource
  1745.  
  1746.         TypeValue= 15 # :nodoc:
  1747.  
  1748.         ##
  1749.         # Creates a new MX record with +preference+, accepting mail at
  1750.         # +exchange+.
  1751.  
  1752.         def initialize(preference, exchange)
  1753.           @preference = preference
  1754.           @exchange = exchange
  1755.         end
  1756.  
  1757.         ##
  1758.         # The preference for this MX.
  1759.  
  1760.         attr_reader :preference
  1761.  
  1762.         ##
  1763.         # The host of this MX.
  1764.  
  1765.         attr_reader :exchange
  1766.  
  1767.         def encode_rdata(msg) # :nodoc:
  1768.           msg.put_pack('n', @preference)
  1769.           msg.put_name(@exchange)
  1770.         end
  1771.  
  1772.         def self.decode_rdata(msg) # :nodoc:
  1773.           preference, = msg.get_unpack('n')
  1774.           exchange = msg.get_name
  1775.           return self.new(preference, exchange)
  1776.         end
  1777.       end
  1778.  
  1779.       ##
  1780.       # Unstructured text resource.
  1781.  
  1782.       class TXT < Resource
  1783.  
  1784.         TypeValue = 16 # :nodoc:
  1785.  
  1786.         def initialize(first_string, *rest_strings)
  1787.           @strings = [first_string, *rest_strings]
  1788.         end
  1789.  
  1790.         ##
  1791.         # Returns an Array of Strings for this TXT record.
  1792.  
  1793.         attr_reader :strings
  1794.  
  1795.         ##
  1796.         # Returns the first string from +strings+.
  1797.  
  1798.         def data
  1799.           @strings[0]
  1800.         end
  1801.  
  1802.         def encode_rdata(msg) # :nodoc:
  1803.           msg.put_string_list(@strings)
  1804.         end
  1805.  
  1806.         def self.decode_rdata(msg) # :nodoc:
  1807.           strings = msg.get_string_list
  1808.           return self.new(*strings)
  1809.         end
  1810.       end
  1811.  
  1812.       ##
  1813.       # A Query type requesting any RR.
  1814.  
  1815.       class ANY < Query
  1816.         TypeValue = 255 # :nodoc:
  1817.       end
  1818.  
  1819.       ClassInsensitiveTypes = [ # :nodoc:
  1820.         NS, CNAME, SOA, PTR, HINFO, MINFO, MX, TXT, ANY
  1821.       ]
  1822.  
  1823.       ##
  1824.       # module IN contains ARPA Internet specific RRs.
  1825.  
  1826.       module IN
  1827.  
  1828.         ClassValue = 1 # :nodoc:
  1829.  
  1830.         ClassInsensitiveTypes.each {|s|
  1831.           c = Class.new(s)
  1832.           c.const_set(:TypeValue, s::TypeValue)
  1833.           c.const_set(:ClassValue, ClassValue)
  1834.           ClassHash[[s::TypeValue, ClassValue]] = c
  1835.           self.const_set(s.name.sub(/.*::/, ''), c)
  1836.         }
  1837.  
  1838.         ##
  1839.         # IPv4 Address resource
  1840.  
  1841.         class A < Resource
  1842.           TypeValue = 1
  1843.           ClassValue = IN::ClassValue
  1844.           ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
  1845.  
  1846.           ##
  1847.           # Creates a new A for +address+.
  1848.  
  1849.           def initialize(address)
  1850.             @address = IPv4.create(address)
  1851.           end
  1852.  
  1853.           ##
  1854.           # The Resolv::IPv4 address for this A.
  1855.  
  1856.           attr_reader :address
  1857.  
  1858.           def encode_rdata(msg) # :nodoc:
  1859.             msg.put_bytes(@address.address)
  1860.           end
  1861.  
  1862.           def self.decode_rdata(msg) # :nodoc:
  1863.             return self.new(IPv4.new(msg.get_bytes(4)))
  1864.           end
  1865.         end
  1866.  
  1867.         ##
  1868.         # Well Known Service resource.
  1869.  
  1870.         class WKS < Resource
  1871.           TypeValue = 11
  1872.           ClassValue = IN::ClassValue
  1873.           ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
  1874.  
  1875.           def initialize(address, protocol, bitmap)
  1876.             @address = IPv4.create(address)
  1877.             @protocol = protocol
  1878.             @bitmap = bitmap
  1879.           end
  1880.  
  1881.           ##
  1882.           # The host these services run on.
  1883.  
  1884.           attr_reader :address
  1885.  
  1886.           ##
  1887.           # IP protocol number for these services.
  1888.  
  1889.           attr_reader :protocol
  1890.  
  1891.           ##
  1892.           # A bit map of enabled services on this host.
  1893.           #
  1894.           # If protocol is 6 (TCP) then the 26th bit corresponds to the SMTP
  1895.           # service (port 25).  If this bit is set, then an SMTP server should
  1896.           # be listening on TCP port 25; if zero, SMTP service is not
  1897.           # supported.
  1898.  
  1899.           attr_reader :bitmap
  1900.  
  1901.           def encode_rdata(msg) # :nodoc:
  1902.             msg.put_bytes(@address.address)
  1903.             msg.put_pack("n", @protocol)
  1904.             msg.put_bytes(@bitmap)
  1905.           end
  1906.  
  1907.           def self.decode_rdata(msg) # :nodoc:
  1908.             address = IPv4.new(msg.get_bytes(4))
  1909.             protocol, = msg.get_unpack("n")
  1910.             bitmap = msg.get_bytes
  1911.             return self.new(address, protocol, bitmap)
  1912.           end
  1913.         end
  1914.  
  1915.         ##
  1916.         # An IPv6 address record.
  1917.  
  1918.         class AAAA < Resource
  1919.           TypeValue = 28
  1920.           ClassValue = IN::ClassValue
  1921.           ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
  1922.  
  1923.           ##
  1924.           # Creates a new AAAA for +address+.
  1925.  
  1926.           def initialize(address)
  1927.             @address = IPv6.create(address)
  1928.           end
  1929.           
  1930.           ##
  1931.           # The Resolv::IPv6 address for this AAAA.
  1932.  
  1933.           attr_reader :address
  1934.  
  1935.           def encode_rdata(msg) # :nodoc:
  1936.             msg.put_bytes(@address.address)
  1937.           end
  1938.  
  1939.           def self.decode_rdata(msg) # :nodoc:
  1940.             return self.new(IPv6.new(msg.get_bytes(16)))
  1941.           end
  1942.         end
  1943.  
  1944.         ##
  1945.         # SRV resource record defined in RFC 2782
  1946.         # 
  1947.         # These records identify the hostname and port that a service is
  1948.         # available at.
  1949.  
  1950.         class SRV < Resource
  1951.           TypeValue = 33
  1952.           ClassValue = IN::ClassValue
  1953.           ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
  1954.  
  1955.           # Create a SRV resource record.
  1956.           #
  1957.           # See the documentation for #priority, #weight, #port and #target
  1958.           # for +priority+, +weight+, +port and +target+ respectively.
  1959.  
  1960.           def initialize(priority, weight, port, target)
  1961.             @priority = priority.to_int
  1962.             @weight = weight.to_int
  1963.             @port = port.to_int
  1964.             @target = Name.create(target)
  1965.           end
  1966.  
  1967.           # The priority of this target host.
  1968.           #
  1969.           # A client MUST attempt to contact the target host with the
  1970.           # lowest-numbered priority it can reach; target hosts with the same
  1971.           # priority SHOULD be tried in an order defined by the weight field.
  1972.           # The range is 0-65535.  Note that it is not widely implemented and
  1973.           # should be set to zero.
  1974.  
  1975.           attr_reader :priority
  1976.  
  1977.           # A server selection mechanism.
  1978.           #
  1979.           # The weight field specifies a relative weight for entries with the
  1980.           # same priority. Larger weights SHOULD be given a proportionately
  1981.           # higher probability of being selected. The range of this number is
  1982.           # 0-65535.  Domain administrators SHOULD use Weight 0 when there
  1983.           # isn't any server selection to do, to make the RR easier to read
  1984.           # for humans (less noisy). Note that it is not widely implemented
  1985.           # and should be set to zero.
  1986.  
  1987.           attr_reader :weight
  1988.  
  1989.           # The port on this target host of this service.
  1990.           #
  1991.           # The range is 0-65535.
  1992.  
  1993.           attr_reader :port
  1994.  
  1995.           # The domain name of the target host.
  1996.           #
  1997.           # A target of "." means that the service is decidedly not available
  1998.           # at this domain.
  1999.  
  2000.           attr_reader :target
  2001.  
  2002.           def encode_rdata(msg) # :nodoc:
  2003.             msg.put_pack("n", @priority)
  2004.             msg.put_pack("n", @weight)
  2005.             msg.put_pack("n", @port)
  2006.             msg.put_name(@target)
  2007.           end
  2008.  
  2009.           def self.decode_rdata(msg) # :nodoc:
  2010.             priority, = msg.get_unpack("n")
  2011.             weight,   = msg.get_unpack("n")
  2012.             port,     = msg.get_unpack("n")
  2013.             target    = msg.get_name
  2014.             return self.new(priority, weight, port, target)
  2015.           end
  2016.         end
  2017.       end
  2018.     end
  2019.   end
  2020.  
  2021.   ##
  2022.   # A Resolv::DNS IPv4 address.
  2023.  
  2024.   class IPv4
  2025.  
  2026.     ##
  2027.     # Regular expression IPv4 addresses must match.
  2028.  
  2029.     Regex = /\A(\d+)\.(\d+)\.(\d+)\.(\d+)\z/
  2030.  
  2031.     def self.create(arg)
  2032.       case arg
  2033.       when IPv4
  2034.         return arg
  2035.       when Regex
  2036.         if (0..255) === (a = $1.to_i) &&
  2037.            (0..255) === (b = $2.to_i) &&
  2038.            (0..255) === (c = $3.to_i) &&
  2039.            (0..255) === (d = $4.to_i)
  2040.           return self.new([a, b, c, d].pack("CCCC"))
  2041.         else
  2042.           raise ArgumentError.new("IPv4 address with invalid value: " + arg)
  2043.         end
  2044.       else
  2045.         raise ArgumentError.new("cannot interpret as IPv4 address: #{arg.inspect}")
  2046.       end
  2047.     end
  2048.  
  2049.     def initialize(address) # :nodoc:
  2050.       unless address.kind_of?(String) && address.length == 4
  2051.         raise ArgumentError.new('IPv4 address must be 4 bytes')
  2052.       end
  2053.       @address = address
  2054.     end
  2055.  
  2056.     ##
  2057.     # A String representation of this IPv4 address.
  2058.  
  2059.     ##
  2060.     # The raw IPv4 address as a String.
  2061.  
  2062.     attr_reader :address
  2063.  
  2064.     def to_s # :nodoc:
  2065.       return sprintf("%d.%d.%d.%d", *@address.unpack("CCCC"))
  2066.     end
  2067.  
  2068.     def inspect # :nodoc:
  2069.       return "#<#{self.class} #{self.to_s}>"
  2070.     end
  2071.  
  2072.     ##
  2073.     # Turns this IPv4 address into a Resolv::DNS::Name.
  2074.  
  2075.     def to_name
  2076.       return DNS::Name.create(
  2077.         '%d.%d.%d.%d.in-addr.arpa.' % @address.unpack('CCCC').reverse)
  2078.     end
  2079.  
  2080.     def ==(other) # :nodoc:
  2081.       return @address == other.address
  2082.     end
  2083.  
  2084.     def eql?(other) # :nodoc:
  2085.       return self == other
  2086.     end
  2087.  
  2088.     def hash # :nodoc:
  2089.       return @address.hash
  2090.     end
  2091.   end
  2092.  
  2093.   ##
  2094.   # A Resolv::DNS IPv6 address.
  2095.  
  2096.   class IPv6
  2097.  
  2098.     ##
  2099.     # IPv6 address format a:b:c:d:e:f:g:h
  2100.     Regex_8Hex = /\A
  2101.       (?:[0-9A-Fa-f]{1,4}:){7}
  2102.          [0-9A-Fa-f]{1,4}
  2103.       \z/x
  2104.  
  2105.     ##
  2106.     # Compressed IPv6 address format a::b
  2107.  
  2108.     Regex_CompressedHex = /\A
  2109.       ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) ::
  2110.       ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)
  2111.       \z/x
  2112.  
  2113.     ##
  2114.     # IPv4 mapped IPv6 address format a:b:c:d:e:f:w.x.y.z
  2115.  
  2116.     Regex_6Hex4Dec = /\A
  2117.       ((?:[0-9A-Fa-f]{1,4}:){6,6})
  2118.       (\d+)\.(\d+)\.(\d+)\.(\d+)
  2119.       \z/x
  2120.  
  2121.     ##
  2122.     # Compressed IPv4 mapped IPv6 address format a::b:w.x.y.z
  2123.  
  2124.     Regex_CompressedHex4Dec = /\A
  2125.       ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) ::
  2126.       ((?:[0-9A-Fa-f]{1,4}:)*)
  2127.       (\d+)\.(\d+)\.(\d+)\.(\d+)
  2128.       \z/x
  2129.  
  2130.     ##
  2131.     # A composite IPv6 address Regexp.
  2132.  
  2133.     Regex = /
  2134.       (?:#{Regex_8Hex}) |
  2135.       (?:#{Regex_CompressedHex}) |
  2136.       (?:#{Regex_6Hex4Dec}) |
  2137.       (?:#{Regex_CompressedHex4Dec})/x
  2138.  
  2139.     ##
  2140.     # Creates a new IPv6 address from +arg+ which may be:
  2141.     #
  2142.     # IPv6:: returns +arg+.
  2143.     # String:: +arg+ must match one of the IPv6::Regex* constants
  2144.  
  2145.     def self.create(arg)
  2146.       case arg
  2147.       when IPv6
  2148.         return arg
  2149.       when String
  2150.         address = ''
  2151.         if Regex_8Hex =~ arg
  2152.           arg.scan(/[0-9A-Fa-f]+/) {|hex| address << [hex.hex].pack('n')}
  2153.         elsif Regex_CompressedHex =~ arg
  2154.           prefix = $1
  2155.           suffix = $2
  2156.           a1 = ''
  2157.           a2 = ''
  2158.           prefix.scan(/[0-9A-Fa-f]+/) {|hex| a1 << [hex.hex].pack('n')}
  2159.           suffix.scan(/[0-9A-Fa-f]+/) {|hex| a2 << [hex.hex].pack('n')}
  2160.           omitlen = 16 - a1.length - a2.length
  2161.           address << a1 << "\0" * omitlen << a2
  2162.         elsif Regex_6Hex4Dec =~ arg
  2163.           prefix, a, b, c, d = $1, $2.to_i, $3.to_i, $4.to_i, $5.to_i
  2164.           if (0..255) === a && (0..255) === b && (0..255) === c && (0..255) === d
  2165.             prefix.scan(/[0-9A-Fa-f]+/) {|hex| address << [hex.hex].pack('n')}
  2166.             address << [a, b, c, d].pack('CCCC')
  2167.           else
  2168.             raise ArgumentError.new("not numeric IPv6 address: " + arg)
  2169.           end
  2170.         elsif Regex_CompressedHex4Dec =~ arg
  2171.           prefix, suffix, a, b, c, d = $1, $2, $3.to_i, $4.to_i, $5.to_i, $6.to_i
  2172.           if (0..255) === a && (0..255) === b && (0..255) === c && (0..255) === d
  2173.             a1 = ''
  2174.             a2 = ''
  2175.             prefix.scan(/[0-9A-Fa-f]+/) {|hex| a1 << [hex.hex].pack('n')}
  2176.             suffix.scan(/[0-9A-Fa-f]+/) {|hex| a2 << [hex.hex].pack('n')}
  2177.             omitlen = 12 - a1.length - a2.length
  2178.             address << a1 << "\0" * omitlen << a2 << [a, b, c, d].pack('CCCC')
  2179.           else
  2180.             raise ArgumentError.new("not numeric IPv6 address: " + arg)
  2181.           end
  2182.         else
  2183.           raise ArgumentError.new("not numeric IPv6 address: " + arg)
  2184.         end
  2185.         return IPv6.new(address)
  2186.       else
  2187.         raise ArgumentError.new("cannot interpret as IPv6 address: #{arg.inspect}")
  2188.       end
  2189.     end
  2190.  
  2191.     def initialize(address) # :nodoc:
  2192.       unless address.kind_of?(String) && address.length == 16
  2193.         raise ArgumentError.new('IPv6 address must be 16 bytes')
  2194.       end
  2195.       @address = address
  2196.     end
  2197.  
  2198.     ##
  2199.     # The raw IPv6 address as a String.
  2200.  
  2201.     attr_reader :address
  2202.  
  2203.     def to_s # :nodoc:
  2204.       address = sprintf("%X:%X:%X:%X:%X:%X:%X:%X", *@address.unpack("nnnnnnnn"))
  2205.       unless address.sub!(/(^|:)0(:0)+(:|$)/, '::')
  2206.         address.sub!(/(^|:)0(:|$)/, '::')
  2207.       end
  2208.       return address
  2209.     end
  2210.  
  2211.     def inspect # :nodoc:
  2212.       return "#<#{self.class} #{self.to_s}>"
  2213.     end
  2214.  
  2215.     ##
  2216.     # Turns this IPv6 address into a Resolv::DNS::Name.
  2217.     #--
  2218.     # ip6.arpa should be searched too. [RFC3152]
  2219.  
  2220.     def to_name
  2221.       return DNS::Name.new(
  2222.         @address.unpack("H32")[0].split(//).reverse + ['ip6', 'arpa'])
  2223.     end
  2224.  
  2225.     def ==(other) # :nodoc:
  2226.       return @address == other.address
  2227.     end
  2228.  
  2229.     def eql?(other) # :nodoc:
  2230.       return self == other
  2231.     end
  2232.  
  2233.     def hash # :nodoc:
  2234.       return @address.hash
  2235.     end
  2236.   end
  2237.  
  2238.   ##
  2239.   # Default resolver to use for Resolv class methods.
  2240.  
  2241.   DefaultResolver = self.new
  2242.  
  2243.   ##
  2244.   # Address Regexp to use for matching IP addresses.
  2245.  
  2246.   AddressRegex = /(?:#{IPv4::Regex})|(?:#{IPv6::Regex})/
  2247.  
  2248. end
  2249.  
  2250.